<template>
    <div class="upload-file">
        <el-upload ref="UploadRef" :file-list="fileList" list-type="picture-card" :accept="onlyImg ? 'image/*' : null" :auto-upload="false" :multiple="multiple" :limit="limit" :disabled="disabled" action="" v-bind="$attrs" :on-change="onChange" :on-exceed="onExceed" :on-error="onError">
            <el-icon>
                <Plus />
            </el-icon>

            <template #file="{ file }">
                <div class="custom-thunbail" v-if="!Gx.IsEmpty(file)">
                    <!-- 图片 -->
                    <div v-if="file.isImg" class="imgCon">
                        <img :src="file.displayUrl" />
                    </div>

                    <!-- 文件 -->
                    <div v-else class="fileCon">
                        <p class="icon"><i class="exticon" :class="file.icon"></i></p>
                        <p class="filename">{{ file.fileName }}</p>
                    </div>

                    <el-row class="oper-bg">
                        <el-col class="icon" :span="disabled ? 12 : 8"><i class="iconfont icon-zoom-out" @click="onPreview(file)"></i></el-col>
                        <el-col class="icon" :span="disabled ? 12 : 8"><i class="iconfont icon-icondownload" @click="onDownload(file)"></i></el-col>
                        <el-col class="icon" :span="8"><i class="iconfont icon-delete" @click="onDelete(file)" v-if="!disabled"></i></el-col>
                    </el-row>
                </div>
            </template>
        </el-upload>

        <!-- 图片大图预览 -->
        <FilePreview ref="FilePreviewRef"></FilePreview>
    </div>
</template>

<script lang="ts" setup>
import Gx from "@/gx/Gx";
import { UploadFile, UploadFiles, UploadUserFile } from "element-plus";
import { TipsType, UploadType } from "@/_gx/TsEnums";
import { FileExt } from "@/_gx/Types";

const fileList = ref<Array<any>>([]);

const props = defineProps({
    //调用时，传过来的v-model对应的接收的属性
    modelValue: [Array],

    //选择文件时是否可以多选
    multiple: {
        type: Boolean,
        default: true,
    },

    //上传数量限制，不限制给0
    limit: {
        type: Number,
        default: 0,
    },

    //是否禁用
    disabled: {
        type: Boolean,
        default: false,
    },

    //是否为只能上传图片
    onlyImg: {
        type: Boolean,
        default: false,
    },
});

//加载时处理父组件传值
onMounted(() => {
    fileList.value = props.modelValue;
    formatFiles();
    calcAddBtn();
});

//监听属性
watch(
    () => props.modelValue,
    (newVal, oldVal) => {
        fileList.value = Gx.IsEmpty(newVal) ? [] : newVal;
        formatFiles();
        calcAddBtn();
    }
);

//格式化数据，增加一些前端使用到的属性
const formatFiles = () => {
    if (fileList.value == null || fileList.value.length == 0) {
        return;
    }

    for (let i = 0; i < fileList.value.length; i++) {
        let item = fileList.value[i];

        //定义扩展属性
        let extData: FileExt = item;
        extData = Gx.GetFileExtInfo(extData);
        MergeObjs(item, extData);
    }
};

//文件改变
const onChange = (file: any, uploadFiles: Array<any>) => {
    let _extName = Gx.GetUrlFileName(file.name).extName;
    let _isImg =
        Gx.imageExts.findIndex((x) => {
            return x == _extName.toLowerCase();
        }) > -1;

    if (props.onlyImg && !_isImg) {
        App.Tips({ msg: "请选择正确的图片格式！" });
        let index = uploadFiles.findIndex((item) => item.uid == file.uid);
        uploadFiles.splice(index, 1);

        return false;
    }

    App.Upload(file.raw)
        .then((res) => {
            if (Config._UPLOAD_TYPE == UploadType.Local) {
                res = res.data;
            }
            file.url = res.url;
            file.fileName = res.fileName;

            fileList.value.push(file);
            emitData();
        })
        .catch((err) => {
            console.log(err);
        });
};

//文件上传数量超出限制
const onExceed = (files: File[], uploadFiles: UploadUserFile[]) => {
    let msg = `文件上传数量限制最大${props.limit}个，`;
    if (uploadFiles.length == 0) {
        msg += `您选择了${files.length}个！`;
    } else {
        msg += `您已经上传了${uploadFiles.length}个，最多能再选择${props.limit - uploadFiles.length}个！`;
    }

    App.Tips({ msg: msg });
};

//文件上传错误
const onError = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
    App.Tips({ msg: "文件上传失败！", type: TipsType.Error });
};

//图片预览
const FilePreviewRef = ref();
const onPreview = (file: UploadFile) => {
    let idx = fileList.value.findIndex((x) => x.uid == file.uid);
    let previewDatas = fileList.value;
    FilePreviewRef.value.Init(previewDatas, idx);
};

//下载
const onDownload = (file: any) => {
    Gx.DownloadFile(file.url, file.fileName);
};

//删除
const onDelete = (file: UploadFile) => {
    let index = fileList.value.findIndex((x) => x.uid == file.uid);
    fileList.value.splice(index, 1);
    emitData();
};

//计算添加按钮是否显示
const { ctx } = getCurrentInstance() as any;
const calcAddBtn = () => {
    let display: string;
    if (props.limit > 0 && fileList.value?.length >= props.limit) {
        display = "none";
    } else {
        display = "inline-flex";
    }

    if (ctx.$el) {
        ctx.$el.querySelector("div.el-upload").style.display = display;
    }
};

//回传数据
const emitData = () => {
    var data = fileList.value.map((x) => {
        return {
            url: x.url,
            fileName: x.fileName,
        };
    });

    emit("update:modelValue", data);
};

const emit = defineEmits(["update:modelValue"]);
</script>

<style lang="scss" scoped>
@import "@/assets/css/variables.scss";

/* 上传按钮的大小 */
.upload-file :deep() .el-upload {
    width: 80px;
    height: 80px;
    line-height: 89px;
}

/* 上传完预览图大小 */
.upload-file :deep() .el-upload-list--picture-card .el-upload-list__item {
    width: 80px;
    height: 80px;
}

.upload-file :deep() .custom-thunbail {
    position: relative;
    height: 100%;
    width: 100%;
}

.upload-file :deep() .custom-thunbail p {
    text-align: center;
}

.upload-file :deep() .custom-thunbail p.icon .exticon {
    font-size: 36px;
    margin: 0;
}

.upload-file :deep() .custom-thunbail p.filename {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    box-sizing: border-box;
    padding: 0 4px;
    font-size: 12px;
    line-height: 20px;
    white-space: nowrap;
    overflow: hidden;
    background-color: $upload-filename-bg;
}

.upload-file :deep() .custom-thunbail img {
    display: inline-block;
    max-width: 100%;
    max-height: 100%;
}

.imgCon {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.imgCon img {
    max-width: 100%;
    max-height: 100%;
}

.fileCon {
    height: 100%;
    width: 100%;
}

.fileCon .icon {
    height: calc(100% - 20px);
    display: flex;
    justify-content: center;
    align-items: center;
}

/* 禁用状态下隐藏添加按钮 */
.upload-file :deep() .is-disabled .el-upload--picture-card {
    display: none !important;
}

/* 预览样式 */
/* .preview :deep() .el-dialog .el-dialog__body {
    padding-bottom: 20px;
    padding-top: 20px;
    text-align: center;
} */

.oper-bg {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    cursor: default;
    text-align: center;
    color: #fff;
    opacity: 0;
    font-size: 20px;
    background-color: rgba(0, 0, 0, 0.7) !important;
    transition: opacity 0.3s;
    line-height: 78px;
}

.oper-bg:hover {
    opacity: 1;
}

.oper-bg .icon i:hover {
    color: $upload-hover-font;
    cursor: pointer;
}
</style>
